package com.jse;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.SimpleTimeZone;

public class Times {

	private static final Map<String,DateTimeFormatter> FORMATTER_MAP = new HashMap<>(16, 0.25F);
	private static final ThreadLocal<Map<String, SimpleDateFormat>> DATAFORMAT_MAP = new ThreadLocal<Map<String, SimpleDateFormat>>() {
	    @Override
	    protected Map<String, SimpleDateFormat> initialValue() {
	      return new HashMap<String, SimpleDateFormat>();
	    }
	  };
	private static final String ymd="yyyy-MM-dd";
	private static final String ymdhms="yyyy-MM-dd HH:mm:ss";
//	String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
//    FORMATTER = DateTimeFormatter.ofPattern(pattern, Locale.US)
//                                 .withZone(ZoneId.of("GMT"))
	
	public static Date parse(Object o) {
		if(o==null)return null;
		else if(o instanceof Date d)return d;
		else if(o instanceof LocalDateTime d)return Date.from(d.atZone(ZoneId.systemDefault()).toInstant());
		else if(o instanceof Long l)return new Date(l);
		else if(o instanceof Number d)return new Date(d.longValue());
		else if(o instanceof String s) {
			if(s.length()==10) {
				var d=LocalDateTime.parse(s+" 00:00:00",formatter(ymdhms));
				return new Date(d.toInstant(ZoneOffset.UTC).toEpochMilli());
			}else if(s.length()==19) {
				if(s.charAt(10)==' ') {var d=LocalDateTime.parse(s,formatter(ymdhms));
				return new Date(d.toInstant(ZoneOffset.UTC).toEpochMilli());}
			}
			
		}
		return null;
	}

	public static LocalDateTime time(Object o) {
		if(o==null)return null;
		else if(o instanceof Temporal t)return LocalDateTime.from(t);
		else if(o instanceof Long l)return null;
		return null;
	}

	public static String gmt(Date date) {
		var df = simpleFormat("E, dd MMM yyyy HH:mm:ss z", Locale.US);
        df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));
        return df.format(date);
	}

	public static SimpleDateFormat simpleFormat(String fmt) {return simpleFormat(fmt,Locale.getDefault());}
	public static SimpleDateFormat simpleFormat(String fmt,Locale local) {
		var tl = DATAFORMAT_MAP.get();
	    var sdf = tl.get(fmt);
	    if (sdf == null) {
	     if(local!=null)sdf = new SimpleDateFormat(fmt,local);
	     else sdf = new SimpleDateFormat(fmt);
	      tl.put(fmt, sdf);
	    }
	    return sdf;
	}
	static public DateTimeFormatter formatter(String fmt){
		var ret= FORMATTER_MAP.get(fmt);
		if(ret==null) {
			ret=DateTimeFormatter.ofPattern(fmt);
			FORMATTER_MAP.put(fmt,ret);
		}
		return ret;
	}

	public static String format(String fmt){return formatter(fmt).format(Instant.now());}
	public static String format(String fmt,TemporalAccessor d){return formatter(fmt).format(d);}
	public static String format(long t){return formatter(ymdhms).format(Instant.ofEpochSecond(t));}
	public static String format(Date d){
		if(d instanceof java.sql.Date x)return simpleFormat(ymd).format(d);
		return simpleFormat(ymdhms).format(d);
	}
	public static String format(String fmt,Date d){return formatter(fmt).format(d.toInstant());}
	public static String format(){return format(ymdhms);}
	public static String format(TemporalAccessor x){
		if(x instanceof LocalDate d)return formatter(ymd).format(d);
		if(x instanceof LocalTime d)return formatter("HH:mm:ss").format(d);
		return formatter(ymdhms).format(x);
	}
	
	private static final String ISO8601_DATE_FORMAT="yyyy-MM-dd'T'HH:mm:ss'Z'";
	public static String utcTimestamp() {
		Date date = new Date(System.currentTimeMillis());
		SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
		df.setTimeZone(new SimpleTimeZone(0, "GMT"));
		return df.format(date);
	}
	
	public static void main(String[] args) {
		var d=new Date();
		String gmt=gmt(d);
		System.out.println(gmt);
	}
}
